// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// RESTRICTED USE SOURCE CODE
// http://www.magic-software.com/License/restricted.pdf

#ifndef MGCCAMERA_H
#define MGCCAMERA_H

#include "MgcMatrix3.h"
#include "MgcObject.h"
#include "MgcPlane.h"
class MgcBound;


class MgcCamera : public MgcObject
{
    MgcDeclareRTTI;
    MgcDeclareStream;

public:
    // construction
    MgcCamera ();

    // view frustum
    void SetFrustum (MgcReal fNear, MgcReal fFar, MgcReal fLeft,
        MgcReal fRight, MgcReal fTop, MgcReal fBottom);
    void SetFrustumNear (MgcReal fNear);
    void SetFrustumFar (MgcReal fFar);
    void GetFrustum (MgcReal& rfNear, MgcReal& rfFar, MgcReal& rfLeft,
        MgcReal& rfRight, MgcReal& rfTop, MgcReal& rfBottom) const;
    MgcReal GetFrustumNear () const;
    MgcReal GetFrustumFar () const;
    MgcReal GetFrustumLeft () const;
    MgcReal GetFrustumRight () const;
    MgcReal GetFrustumTop () const;
    MgcReal GetFrustumBottom () const;
    MgcReal GetMaxCosSqrFrustumAngle () const;

    // view port (contained in [0,1]^2)
    void SetViewPort (MgcReal fLeft, MgcReal fRight, MgcReal fTop,
        MgcReal fBottom);
    void GetViewPort (MgcReal& rfLeft, MgcReal& rfRight, MgcReal& rfTop,
        MgcReal& rfBottom);
    MgcReal GetViewPortLeft () const;
    MgcReal GetViewPortRight () const;
    MgcReal GetViewPortTop () const;
    MgcReal GetViewPortBottom () const;

    // camera frame (world coordinates)
    //   default location = (0,0,0)
    //   default left = (1,0,0)
    //   default up = (0,1,0)
    //   default direction = (0,0,1)
    void SetFrame (const MgcVector3& rkLocation, const MgcVector3& rkLeft,
        const MgcVector3& rkUp, const MgcVector3& rkDirection);
    void SetFrame (const MgcVector3& rkLocation, const MgcMatrix3& rkAxes);
    void SetLocation (const MgcVector3& rkLocation);
    void SetAxes (const MgcVector3& rkLeft, const MgcVector3& rkUp,
        const MgcVector3& rkDirection);
    void SetAxes (const MgcMatrix3& rkAxes);
    const MgcVector3& GetLocation () const;
    const MgcVector3& GetLeft () const;
    const MgcVector3& GetUp () const;
    const MgcVector3& GetDirection () const;

    // update frustum, viewport, and frame
    void Update ();

    // access to stack of world culling planes
    unsigned int GetPlaneQuantity () const;
    const MgcPlane* GetPlanes () const;
    void PushPlane (const MgcPlane& rkPlane);
    void PopPlane ();

protected:
    // update callbacks
    virtual void OnFrustumChange ();
    virtual void OnViewPortChange ();
    virtual void OnFrameChange ();

    // culling support in MgcSpatial::OnDraw
    friend class MgcSpatial;
    void SetPlaneState (unsigned int uiPlaneState);
    unsigned int GetPlaneState () const;
    bool Culled (const MgcBound& kWorldBound);

    // culling support in MgcPortal::Draw
    friend class MgcPortal;
    bool Culled (unsigned int uiVertexQuantity, const MgcVector3* akVertex,
        bool bIgnoreNearPlane);

    // view frustum
    MgcReal m_fFrustumN, m_fFrustumF;
    MgcReal m_fFrustumL, m_fFrustumR, m_fFrustumT, m_fFrustumB;

    // view port
    MgcReal m_fPortL, m_fPortR, m_fPortT, m_fPortB;

    // camera frame (world location and coordinate axes)
    MgcVector3 m_kLocation, m_kLeft, m_kUp, m_kDirection;

    // Temporary values computed in OnFrustumChange that are needed if a
    // call is made to OnFrameChange.
    MgcReal m_afCoeffL[2], m_afCoeffR[2], m_afCoeffB[2], m_afCoeffT[2];

    // Bit flag to store whether or not a plane is active in the culling
    // system.  A bit of 1 means the plane is active, otherwise the plane is
    // inactive.  The first 6 planes are the view frustum planes.  Indices
    // are:  0 = near, 1 = far, 2 = left, 3 = right, 4 = bottom, 5 = top.
    // The system currently supports at most 32 culling planes.
    unsigned int m_uiPlaneState;

    // world planes
    enum
    {
        CAM_LEFT_PLANE = 0,
        CAM_RIGHT_PLANE = 1,
        CAM_BOTTOM_PLANE = 2,
        CAM_TOP_PLANE = 3,
        CAM_FAR_PLANE = 4,
        CAM_NEAR_PLANE = 5,
        CAM_FRUSTUM_PLANES = 6,
        CAM_MAX_WORLD_PLANES = 32
    };
    unsigned int m_uiPlaneQuantity;
    MgcPlane m_akWorldPlane[CAM_MAX_WORLD_PLANES];
};

MgcSmartPointer(MgcCamera);
MgcRegisterStream(MgcCamera);
#include "MgcCamera.inl"

#endif
